<?php
// $Id$

/**
 * @file
 */

/**
 * Get the display name of available point systems.
 *
 * @return array An associative array containing the point system id as the key
 *   and display name as the value.
 * 
 * @see guild_get_games()
 */
function guild_get_point_systems() {
  $config = guild_point_system_config();
  $systems = array();
  
  foreach ($config as $id => $info) {
    $systems[$id] = $info['name'];
  }
  
  return $systems;
}

/**
 * Discover all modules implementing hook_guild_point_system() and aggregate the
 * data.
 */
function guild_point_system_config() {
  $point_systems = array();
  
  // Sadly module_invoke_all() is out of the question since we need the module
  // name.
  foreach (module_implements('guild_point_system') as $module) {
    $function = $module . '_guild_point_system';
    
    // There can be multiple point systems defined in a single module; get data
    // on all of them.
    foreach ($function() as $system => $info) {
      if (empty($system)) {
        $t_args = array('%module-id' => $module, '%system-id' => $info['name']);
        drupal_set_message(t('The module %module-id contains an invalid identifier for the system %system-id.', $t_args), 'error');
        continue;
      }
      
      // Note that if there is a point system id conflict, existing listings do
      // not store the module name, so there is no way to prevent screwy things
      // from happening here if the wrong module is loaded after the original.
      
      $point_systems[$system] = $info;
      $point_systems[$system]['module'] = $module;
    }
  }
  
  return $point_systems;
}

/**
 *
 */
function guild_standings_overview() {
  $point_systems = guild_get_point_systems();
  
  $form['header'] = array(
    '#type' => 'value',
    '#value' => array(
      array('data' => t('Title'), 'field' => 'title', 'sort' => 'asc'),
      array('data' => t('Point system'), 'field' => 'point_system'),
      array('data' => t('Operations'), 'colspan' => 2)
    )
  );
  
  $result = db_query(
    "SELECT listing_id AS id, title, comment, point_system " .
    "FROM {guild_listing} " .
    tablesort_sql($form['header']['#value'])
  );
  
  while ($listing = db_fetch_object($result)) {
    $form['title'][$listing->id] = array('#value' => check_plain($listing->title));
    $form['comment'][$listing->id] = array('#value' => check_plain(truncate_utf8($listing->comment, 36, FALSE, TRUE)));
    
    $system_name = t('(not found)');
    if (isset($point_systems[$listing->point_system])) {
      $system_name = $point_systems[$listing->point_system];
    }
    else {
      drupal_set_message(t('The point system of one or more listings could not be determined. ' .
        'This may be caused by a recently disabled or uninstalled point system module.'), 'error', FALSE);
    }
    
    $form['point_system'][$listing->id] = array('#value' => $system_name);
    $form['options'][$listing->id]      = array('#value' => l(t('options'), 'admin/guild/standings/' . $listing->id . '/options'),);
    $form['edit'][$listing->id]         = array('#value' => l(t('edit'),    'admin/guild/standings/' . $listing->id . '/edit'));
    $form['delete'][$listing->id]       = array('#value' => l(t('delete'),  'admin/guild/standings/' . $listing->id . '/delete'));
  }
  
  return $form;
}

/**
 *
 *
 * @ingroup themeable
 */
function theme_guild_standings_overview($form) {
  drupal_add_css(drupal_get_path('module', 'guild') . '/guild.css');
  $rows = array();
  
  if (isset($form['title']) && is_array($form['title'])) {
    foreach (element_children($form['title']) as $id) {
      $comment = empty($form['comment'][$id]) ? '&nbsp;' : drupal_render($form['comment'][$id]);
      $title = drupal_render($form['title'][$id]);
      $title .= '<div class="guild-description">' . $comment . "</div>";
      
      $point_system = drupal_render($form['point_system'][$id]);
      if (isset($form['options'][$id])) {
        $point_system .= '<div class="guild-standing-option">' . drupal_render($form['options'][$id]) . "</div>";
      }
      
      $row = array();
      $row[] = $title;
      $row[] = $point_system;
      $row[] = drupal_render($form['edit'][$id]);
      $row[] = drupal_render($form['delete'][$id]);
      
      $rows[] = $row;
    }
  }
  else {
    $rows[] = array(array('data' => t('No standings available.'), 'colspan' => 4));
  }
  
  $output = theme('table', $form['header']['#value'], $rows);
  $output .= drupal_render($form);
  
  return $output;
}

/**
 *
 */
function guild_listing_edit($form_state, $op, $listing = NULL) {
  if (empty($listing) || $op == 'add') {
    $listing = array(
      'listing_id' => NULL,
      'title' => '',
      'comment' => '',
      'point_system' => 'guild_none'
    );
  }
  else {
    drupal_set_title(t('Standings: @standing', array('@standing' => $listing['title'])));
  }
  
  $point_systems = guild_get_point_systems();
  if (!empty($listing['point_system']) && !isset($point_systems[$listing['point_system']])) {
    $point_systems = array($listing['point_system'] => t('(point system not found)'));
    drupal_set_message(t('The selected point system for this listing cannot be found. ' .
      'This may be caused by a recently disabled or uninstalled point system module.'), 'error');
  }
  //else if (empty($point_systems)) {
  //  // @todo Consider adding a destination query back to this page.
  //  $t_args = array('@enable-module' => url('admin/build/modules'));
  //  drupal_set_message(t('You must <a href="@enable-module">enable a point system module</a> to create a listing.', $t_args), 'error');
  //  drupal_goto('admin/guild/standings');
  //}
  //else {
  //  $point_systems = array_merge(array('' => t('(no point system selected)')), $point_systems);
  //}
  
  $form['listing_op'] = array('#type' => 'value', '#value' => $op);
  $form['listing_id'] = array('#type' => 'value', '#value' => $listing['listing_id']);
  
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => t('Listing title'),
    '#default_value' => $listing['title'],
    '#maxlength' => 64,
    '#required' => TRUE
  );
  
  $form['comment'] = array(
    '#type' => 'textarea',
    '#title' => t('Listing comment'),
    '#default_value' => $listing['comment'],
    '#rows' => 2
  );
  
  // @todo Check consequences of disabling this field when a point system module has been uninstalled, leaving the listing in no man's land.
  $form['point_system'] = array(
    '#type' => 'select',
    '#title' => t('Point system'),
    '#description' => t("The point system to use when calculating values. " .
      "See the selected point system's documentation for more details.<br />" .
      "<strong>Warning! This field cannot be changed after a listing has been created.</strong>"),
    '#options' => $point_systems,
    '#default_value' => $listing['point_system'],
    '#required' => TRUE,
    '#disabled' => $op == 'edit' ? TRUE : FALSE
  );
  
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => $op == 'add' ? t('Save') : t('Update')
  );
  
  return $form;
}

/**
 *
 */
function guild_listing_edit_validate($form, &$form_state) {
  $listing = $form_state['values'];
  
  // NOTE: Since the point system field is required, it's automatically validated.
  
  // Make sure listing titles are unique since they show up on the menu.
  if ($listing['listing_op'] == 'edit') {
    $query = db_query(
      "SELECT listing_id FROM {guild_listing} WHERE title = '%s' AND listing_id <> %d",
      $listing['title'], $listing['listing_id']
    );
  }
  else {
    $query = db_query("SELECT listing_id FROM {guild_listing} WHERE title = '%s'", $listing['title']);
  }
  
  if (db_fetch_object($query) !== FALSE) {
    form_set_error('title', t('A listing with that name already exists.'));
  }
}

/**
 *
 */
function guild_listing_edit_submit($form, &$form_state) {
  guild_save_listing($form_state['values']);
  $form_state['redirect'] = 'admin/guild/standings';
}

/**
 *
 */
function guild_listing_delete_confirm(&$form_state, $op, $listing) {
  $form['listing_op'] = array('#type' => 'value', '#value' => $op);
  $form['listing_id'] = array('#type' => 'value', '#value' => $listing['listing_id']);
  
  $form['title'] = array('#type' => 'value', '#value' => $listing['title']);
  
  // @todo Mention how many raids are associated with the listing to help prevent people from accidently deleting listings containing data.
  
  $message = t('Are you sure you want to delete the %standing listing?', array('%standing' => $listing['title']));
  $caption = '<p>' . t('This action cannot be undone.') . '</p>';
  
  return confirm_form($form, $message, 'admin/guild/standings', $caption, t('Delete'));
}

/**
 *
 */
function guild_listing_delete_confirm_submit($form, &$form_state) {
  guild_save_listing($form_state['values']);
  
  $t_args = array('%standing' => $form_state['values']['title']);
  drupal_set_message(t('The listing %standing has been deleted.', $t_args));
  
  $form_state['redirect'] = 'admin/guild/standings';
  return;
}

/**
 * Manages listing entries and menu links.
 *
 * @param array $edit
 *   An associative array describing the listing and the operation to perform.
 */
function guild_save_listing($edit) {
  $link_path = 'standings/';
  $t_args = array('%standing' => $edit['title']);
  
  // @todo Change implementation to use drupal_write_record().
  // This avoids problems with db_last_insert_id() not functioning as expected
  // for third-party developers.
  
  if ($edit['listing_op'] == 'add') {
    db_query(
      "INSERT INTO {guild_listing} (title, comment, point_system) " .
      "VALUES ('%s', '%s', '%s')",
      $edit['title'], $edit['comment'], $edit['point_system']
    );
    
    $listing_id = db_last_insert_id('guild_listing', 'listing_id');
    watchdog('guild', 'standings: created new listing %standing', $t_args, WATCHDOG_NOTICE, l(t('edit'), 'admin/guild/standings/' . $listing_id . '/edit'));
    
    $link_path .= $listing_id;
    $op = 'insert';
  }
  else if ($edit['listing_op'] == 'edit') {
    db_query(
      "UPDATE {guild_listing} SET title = '%s', comment = '%s', point_system = '%s' " .
      "WHERE listing_id = %d",
      $edit['title'], $edit['comment'], $edit['point_system'], $edit['listing_id']
    );
    watchdog('guild', 'standings: updated listing %standing', $t_args, WATCHDOG_NOTICE, l(t('edit'), 'admin/guild/standings/' . $edit['listing_id'] . '/edit'));
    
    $link_path .= $edit['listing_id'];
    $op = 'update';
  }
  else if ($edit['listing_op'] == 'delete') {
    db_query("DELETE FROM {guild_listing} WHERE listing_id = %d", $edit['listing_id']);
    watchdog('guild', 'standings: deleted the listing %standing', $t_args);
    
    // @todo Delete the associated events of a deleted listing.
    
    $link_path .= $edit['listing_id'];
    $op = 'delete';
  }
  
  if (isset($op)) {
    // Note that this will not change customized links (Site building > Menus).
    menu_link_maintain('guild', $op, $link_path, $edit['title']);
  }
}

/**
 * Build a form control containing a list of the standings pages defined by the
 * user. This control will be disabled if there are none.
 *
 * @param string $type
 *   The picker type, either 'select' or 'checkboxes'.
 * @param boolean $required
 *   Should this be a required form element.
 * @param string $title
 *   A custom form title for the picker.
 *
 * @return array A Form API array containing a standings picker.
 */
function guild_standings_picker($type = 'select', $required = TRUE, $title = '') {
  $query = db_query("SELECT listing_id, title FROM {guild_listing}");
  
  while ($result = db_fetch_object($query)) {
    // Note that check_plain is automatically called for select boxes (see http://drupal.org/node/28984).
    $listings[$result->listing_id] = ($type == 'select') ? $result->title : check_plain($result->title);
  }
  
  if (!empty($listings)) {
    $default_listing = array_shift(array_keys($listings));
  }
  else {
    $listings = array('' => t('(no listings defined)'));
    $default_listing = '';
  }
  
  return array(
    '#type' => $type,
    '#title' => empty($title) ? t('Listing') : $title,
    '#options' => $listings,
    '#default_value' => $default_listing,
    '#required' => $required,
    '#disabled' => $default_listing == '' ? TRUE : FALSE
  );
}
